Typical HAL I3C use cases for migration

This section provides information about typical HAL I3C use cases for migration.

Use case: HAL I3C controller transmit direct write CCC command

Sequence diagram

  @startuml
  participant "Application" as App
  participant "I3C" as I3C

  App -> I3C: HAL_I3C_Init()
  App -> I3C: HAL_I3C_Ctrl_Config()
  App -> I3C: HAL_I3C_AddDescToFrame()
  App -> I3C: HAL_I3C_Ctrl_TransmitCCC() / HAL_I3C_Ctrl_TransmitCCC_IT() / HAL_I3C_Ctrl_TransmitCCC_DMA()
  @enduml

Code snippet

HAL1

HAL2

I3C_HandleTypeDef hi3c1;
I3C_CtrlConfTypeDef sCtrlConfig = {0};
I3C_XferTypeDef xferData;
I3C_PrivateTypeDef privateDesc;
I3C_CCCTypeDef cccDesc;
uint8_t ccc_buffer[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t txBuffer[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t rx_buffer[8]  = {0};
uint32_t ctrlBuffer[2] = {0};
uint32_t status_buffer[2] = {0};

// Initialize I3C peripheral
hi3c1.Instance = I3C1;
hi3c1.Mode = HAL_I3C_MODE_CONTROLLER;
hi3c1.Init.CtrlBusCharacteristic.SDAHoldTime = HAL_I3C_SDA_HOLD_TIME_1_5;
hi3c1.Init.CtrlBusCharacteristic.WaitTime = HAL_I3C_OWN_ACTIVITY_STATE_0;
hi3c1.Init.CtrlBusCharacteristic.SCLPPLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI3CHighDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLODLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI2CHighDuration = 0x00;
hi3c1.Init.CtrlBusCharacteristic.BusFreeDuration = 0x32;
hi3c1.Init.CtrlBusCharacteristic.BusIdleDuration = 0xf8;
HAL_I3C_Init(&hi3c1);

// Configure controller
sCtrlConfig.DynamicAddr = 0;
sCtrlConfig.StallTime = 0x10;
sCtrlConfig.HotJoinAllowed = DISABLE;
sCtrlConfig.ACKStallState = DISABLE;
sCtrlConfig.CCCStallState = ENABLE;
sCtrlConfig.TxStallState = DISABLE;
sCtrlConfig.RxStallState = DISABLE;
sCtrlConfig.HighKeeperSDA = DISABLE;
HAL_I3C_Ctrl_Config(&hi3c1, &sCtrlConfig);

// Fill CCC descriptor
cccDesc.TargetAddr = 0x22;
cccDesc.CCC = 0x85;
cccDesc.CCCBuf.pBuffer = ccc_buffer;
cccDesc.CCCBuf.Size = sizeof(ccc_buffer);
cccDesc.Direction = 0;

// Fill Private descriptor
privateDesc.TargetAddr = 0x22;
privateDesc.TxBuf.pBuffer = txBuffer;
privateDesc.TxBuf.Size = sizeof(txBuffer);
privateDesc.RxBuf.pBuffer = rx_buffer;
privateDesc.RxBuf.Size = sizeof(rx_buffer);
privateDesc.Direction = 0;

// Fill transfer structure
xferData.CtrlBuf.pBuffer = ctrlBuffer;
xferData.CtrlBuf.Size = 2;
xferData.StatusBuf.pBuffer = status_buffer;
xferData.StatusBuf.Size = 2;
xferData.TxBuf.pBuffer = txBuffer;
xferData.TxBuf.Size = sizeof(txBuffer);
xferData.RxBuf.pBuffer = rx_buffer;
xferData.RxBuf.Size = sizeof(rx_buffer);

uint8_t nbFrame = 1;
uint32_t option = 0;

// Add descriptors to frame
HAL_StatusTypeDef status = HAL_I3C_AddDescToFrame(
    &hi3c1,
    &cccDesc,
    &privateDesc,
    &xferData,
    nbFrame,
    option
);

// Start transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_Ctrl_TransmitCCC(&hi3c1, &xferData, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CtrlTxCpltCallback */
HAL_I3C_Ctrl_TransmitCCC_IT(&hi3c1, &xferData);
HAL_I3C_Ctrl_TransmitCCC_DMA(&hi3c1, &xferData);
hal_i3c_handle_t hi3c1;
hal_i3c_ctrl_config_t sCtrlConfig;
hal_i3c_transfer_ctx_t xfer_ctx;
hal_i3c_ccc_desc_t ccc_desc;
uint32_t ctrl_buf[2] = {0x12345678, 0x9ABCDEF0};
uint8_t tx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t ccc_data[4] = {0xAA, 0xBB, 0xCC, 0xDD};















// Initialize I3C peripheral
HAL_I3C_Init(&hi3c1, HAL_I3C1);


// Configure controller
sCtrlConfig.scl_waveform = 0xFFFFFFFF;
sCtrlConfig.timing = 0xFFFFFFFF;
HAL_I3C_CTRL_SetConfig(&hi3c1, &sCtrlConfig);

// Configure stall time
HAL_I3C_CTRL_SetConfigStallTime(&hi3c1, 0x10, HAL_I3C_CTRL_STALL_CCC);

// Fill CCC descriptor
ccc_desc.tgt_addr = 0x7E;
ccc_desc.ccc = 0x06;
ccc_desc.data_size_byte = sizeof(ccc_data);
ccc_desc.direction = HAL_I3C_DIRECTION_WRITE;

// Initialize transfer context
xfer_ctx.p_tc_data = NULL;
xfer_ctx.tc_size_word = 0;
xfer_ctx.p_tx_data = ccc_data;
xfer_ctx.tx_size_byte = sizeof(ccc_data);
xfer_ctx.p_rx_data = NULL;
xfer_ctx.rx_size_byte = 0;
xfer_ctx.transfer_mode = HAL_I3C_CCC_BROADCAST_WITH_DEFBYTE_STOP;
xfer_ctx.nb_tx_frame = 1;









HAL_I3C_CTRL_InitTransferCtxTc(&xfer_ctx, ctrl_buf, 2);
HAL_I3C_CTRL_InitTransferCtxTx(&xfer_ctx, tx_buf, sizeof(tx_buf));

// Build CCC transfer context
HAL_I3C_CTRL_BuildTransferCtxCCC(&xfer_ctx, &ccc_desc, 1, HAL_I3C_CCC_BROADCAST_WITH_DEFBYTE_STOP);





// Start the I3C transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_CTRL_Transfer(&hi3c1, &xfer_ctx, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CTRL_TransferCpltCallback */
HAL_I3C_CTRL_Transfer_IT(&hi3c1, &xfer_ctx);
HAL_I3C_CTRL_Transfer_DMA(&hi3c1, &xfer_ctx);

Key changes

  1. HAL2 applies controller configuration using HAL_I3C_CTRL_SetConfig() and configures stall time using HAL_I3C_CTRL_SetConfigStallTime().

  2. HAL2 builds a transfer context using HAL_I3C_CTRL_InitTransferCtx*() and HAL_I3C_CTRL_BuildTransferCtxCCC().

  3. HAL2 starts the transfer using HAL_I3C_CTRL_Transfer*() instead of HAL_I3C_Ctrl_TransmitCCC*().

Use case: HAL I3C controller receive direct read CCC command

Sequence diagram

  @startuml
  participant "Application" as App
  participant "I3C" as I3C

  App -> I3C: HAL_I3C_Init()
  App -> I3C: HAL_I3C_Ctrl_Config()
  App -> I3C: HAL_I3C_AddDescToFrame()
  App -> I3C: HAL_I3C_Ctrl_ReceiveCCC() / HAL_I3C_Ctrl_ReceiveCCC_IT() / HAL_I3C_Ctrl_ReceiveCCC_DMA()
  @enduml

Code snippet

HAL1

HAL2

I3C_HandleTypeDef hi3c1;
I3C_CtrlConfTypeDef sCtrlConfig = {0};
I3C_XferTypeDef xferData;
I3C_PrivateTypeDef privateDesc;
I3C_CCCTypeDef cccDesc;
uint8_t ccc_buffer[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t txBuffer[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t rx_buffer[8]  = {0};
uint32_t ctrlBuffer[2] = {0};
uint32_t status_buffer[2] = {0};

// Initialize I3C peripheral
hi3c1.Instance = I3C1;
hi3c1.Mode = HAL_I3C_MODE_CONTROLLER;
hi3c1.Init.CtrlBusCharacteristic.SDAHoldTime = HAL_I3C_SDA_HOLD_TIME_1_5;
hi3c1.Init.CtrlBusCharacteristic.WaitTime = HAL_I3C_OWN_ACTIVITY_STATE_0;
hi3c1.Init.CtrlBusCharacteristic.SCLPPLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI3CHighDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLODLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI2CHighDuration = 0x00;
hi3c1.Init.CtrlBusCharacteristic.BusFreeDuration = 0x32;
hi3c1.Init.CtrlBusCharacteristic.BusIdleDuration = 0xf8;
HAL_I3C_Init(&hi3c1);

// Configure controller
sCtrlConfig.DynamicAddr = 0;
sCtrlConfig.StallTime = 0x10;
sCtrlConfig.HotJoinAllowed = DISABLE;
sCtrlConfig.ACKStallState = DISABLE;
sCtrlConfig.CCCStallState = ENABLE;
sCtrlConfig.TxStallState = DISABLE;
sCtrlConfig.RxStallState = DISABLE;
sCtrlConfig.HighKeeperSDA = DISABLE;
HAL_I3C_Ctrl_Config(&hi3c1, &sCtrlConfig);

// Fill CCC descriptor
cccDesc.TargetAddr = 0x22;
cccDesc.CCC = 0x85;
cccDesc.CCCBuf.pBuffer = ccc_buffer;
cccDesc.CCCBuf.Size = sizeof(ccc_buffer);
cccDesc.Direction = 0;

// Fill Private descriptor
privateDesc.TargetAddr = 0x22;
privateDesc.TxBuf.pBuffer = txBuffer;
privateDesc.TxBuf.Size = sizeof(txBuffer);
privateDesc.RxBuf.pBuffer = rx_buffer;
privateDesc.RxBuf.Size = sizeof(rx_buffer);
privateDesc.Direction = 0;

// Fill transfer structure
xferData.CtrlBuf.pBuffer = ctrlBuffer;
xferData.CtrlBuf.Size = 2;
xferData.StatusBuf.pBuffer = status_buffer;
xferData.StatusBuf.Size = 2;
xferData.TxBuf.pBuffer = txBuffer;
xferData.TxBuf.Size = sizeof(txBuffer);
xferData.RxBuf.pBuffer = rx_buffer;
xferData.RxBuf.Size = sizeof(rx_buffer);

uint8_t nbFrame = 1;
uint32_t option = 0;

// Add descriptors to frame
HAL_StatusTypeDef status = HAL_I3C_AddDescToFrame(
    &hi3c1,
    &cccDesc,
    &privateDesc,
    &xferData,
    nbFrame,
    option
);

// Start transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_Ctrl_ReceiveCCC(&hi3c1, &xferData, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CtrlRxCpltCallback */
HAL_I3C_Ctrl_ReceiveCCC_IT(&hi3c1, &xferData);
HAL_I3C_Ctrl_ReceiveCCC_DMA(&hi3c1, &xferData);
hal_i3c_handle_t hi3c1;
hal_i3c_ctrl_config_t sCtrlConfig;
hal_i3c_transfer_ctx_t xfer_ctx;
hal_i3c_ccc_desc_t ccc_desc;
uint32_t ctrl_buf[2] = {0x12345678, 0x9ABCDEF0};
uint8_t rx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t ccc_data[4] = {0xAA, 0xBB, 0xCC, 0xDD};















// Initialize I3C peripheral
HAL_I3C_Init(&hi3c1, HAL_I3C1);


// Configure controller
sCtrlConfig.scl_waveform = 0xFFFFFFFF;
sCtrlConfig.timing = 0xFFFFFFFF;
HAL_I3C_CTRL_SetConfig(&hi3c1, &sCtrlConfig);

// Configure stall time
HAL_I3C_CTRL_SetConfigStallTime(&hi3c1, 0x10, HAL_I3C_CTRL_STALL_CCC);

// Fill CCC descriptor
ccc_desc.tgt_addr = 0x7E;
ccc_desc.ccc = 0x06;
ccc_desc.data_size_byte = sizeof(ccc_data);
ccc_desc.direction = HAL_I3C_DIRECTION_READ;

// Initialize transfer context
xfer_ctx.p_tc_data = NULL;
xfer_ctx.tc_size_word = 0;
xfer_ctx.p_tx_data = ccc_data;
xfer_ctx.tx_size_byte = sizeof(ccc_data);
xfer_ctx.p_rx_data = NULL;
xfer_ctx.rx_size_byte = 0;
xfer_ctx.transfer_mode = HAL_I3C_CCC_BROADCAST_WITH_DEFBYTE_STOP;
xfer_ctx.nb_tx_frame = 1;









HAL_I3C_CTRL_InitTransferCtxTc(&xfer_ctx, ctrl_buf, 2);
HAL_I3C_CTRL_InitTransferCtxRx(&xfer_ctx, rx_buf, sizeof(rx_buf));

// Build CCC transfer context
HAL_I3C_CTRL_BuildTransferCtxCCC(&xfer_ctx, &ccc_desc, 1, HAL_I3C_CCC_BROADCAST_WITH_DEFBYTE_STOP);





// Start the I3C transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_CTRL_Transfer(&hi3c1, &xfer_ctx, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CTRL_TransferCpltCallback */
HAL_I3C_CTRL_Transfer_IT(&hi3c1, &xfer_ctx);
HAL_I3C_CTRL_Transfer_DMA(&hi3c1, &xfer_ctx);

Key changes

  1. HAL2 applies controller configuration using HAL_I3C_CTRL_SetConfig() and configures stall time using HAL_I3C_CTRL_SetConfigStallTime().

  2. HAL2 builds a transfer context using HAL_I3C_CTRL_InitTransferCtx*() and HAL_I3C_CTRL_BuildTransferCtxCCC().

  3. HAL2 starts the transfer using HAL_I3C_CTRL_Transfer*() instead of HAL_I3C_Ctrl_ReceiveCCC*().

Related examples in HAL2

Example name

Brief

example_ll_i3c_direct_polling_controller

How to use the CRYP peripheral to encrypt/decrypt data(Plaintext/Ciphertext) using CRYP GCM.


Use case: HAL I3C controller private write

Sequence diagram

  @startuml
  participant "Application" as App
  participant "I3C" as I3C

  App -> I3C: HAL_I3C_Init()
  App -> I3C: HAL_I3C_Ctrl_Config()
  App -> I3C: HAL_I3C_AddDescToFrame()
  App -> I3C: HAL_I3C_Ctrl_Transmit() / HAL_I3C_Ctrl_Transmit_IT() / HAL_I3C_Ctrl_Transmit_DMA()
  @enduml

Code snippet

HAL1

HAL2

I3C_HandleTypeDef hi3c1;
I3C_CtrlConfTypeDef sCtrlConfig = {0};
I3C_XferTypeDef xferData;
I3C_PrivateTypeDef privateDesc;
I3C_CCCTypeDef cccDesc;
uint8_t ccc_buffer[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t txBuffer[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t rx_buffer[8]  = {0};
uint32_t ctrlBuffer[2] = {0};
uint32_t status_buffer[2] = {0};

// Initialize I3C peripheral
hi3c1.Instance = I3C1;
hi3c1.Mode = HAL_I3C_MODE_CONTROLLER;
hi3c1.Init.CtrlBusCharacteristic.SDAHoldTime = HAL_I3C_SDA_HOLD_TIME_1_5;
hi3c1.Init.CtrlBusCharacteristic.WaitTime = HAL_I3C_OWN_ACTIVITY_STATE_0;
hi3c1.Init.CtrlBusCharacteristic.SCLPPLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI3CHighDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLODLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI2CHighDuration = 0x00;
hi3c1.Init.CtrlBusCharacteristic.BusFreeDuration = 0x32;
hi3c1.Init.CtrlBusCharacteristic.BusIdleDuration = 0xf8;
HAL_I3C_Init(&hi3c1);

// Configure controller
sCtrlConfig.DynamicAddr = 0;
sCtrlConfig.StallTime = 0x10;
sCtrlConfig.HotJoinAllowed = DISABLE;
sCtrlConfig.ACKStallState = DISABLE;
sCtrlConfig.CCCStallState = ENABLE;
sCtrlConfig.TxStallState = DISABLE;
sCtrlConfig.RxStallState = DISABLE;
sCtrlConfig.HighKeeperSDA = DISABLE;
HAL_I3C_Ctrl_Config(&hi3c1, &sCtrlConfig);

// Fill CCC descriptor
cccDesc.TargetAddr = 0x22;
cccDesc.CCC = 0x85;
cccDesc.CCCBuf.pBuffer = ccc_buffer;
cccDesc.CCCBuf.Size = sizeof(ccc_buffer);
cccDesc.Direction = 0;

// Fill Private descriptor
privateDesc.TargetAddr = 0x22;
privateDesc.TxBuf.pBuffer = txBuffer;
privateDesc.TxBuf.Size = sizeof(txBuffer);
privateDesc.RxBuf.pBuffer = rx_buffer;
privateDesc.RxBuf.Size = sizeof(rx_buffer);
privateDesc.Direction = 0;

// Fill transfer structure
xferData.CtrlBuf.pBuffer = ctrlBuffer;
xferData.CtrlBuf.Size = 2;
xferData.StatusBuf.pBuffer = status_buffer;
xferData.StatusBuf.Size = 2;
xferData.TxBuf.pBuffer = txBuffer;
xferData.TxBuf.Size = sizeof(txBuffer);
xferData.RxBuf.pBuffer = rx_buffer;
xferData.RxBuf.Size = sizeof(rx_buffer);

uint8_t nbFrame = 1;
uint32_t option = 0;

// Add descriptors to frame
HAL_StatusTypeDef status = HAL_I3C_AddDescToFrame(
    &hi3c1,
    &cccDesc,
    &privateDesc,
    &xferData,
    nbFrame,
    option
);

// Start transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_Ctrl_Transmit(&hi3c1, &xferData, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CtrlTxCpltCallback */
HAL_I3C_Ctrl_Transmit_IT(&hi3c1, &xferData);
HAL_I3C_Ctrl_Transmit_DMA(&hi3c1, &xferData);
hal_i3c_handle_t hi3c1;
hal_i3c_ctrl_config_t sCtrlConfig;
hal_i3c_transfer_ctx_t xfer_ctx;
hal_i3c_ccc_desc_t ccc_desc;
uint32_t ctrl_buf[2] = {0x12345678, 0x9ABCDEF0};
uint8_t tx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t tx_data[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};















// Initialize I3C peripheral
HAL_I3C_Init(&hi3c1, HAL_I3C1);


// Configure controller
sCtrlConfig.scl_waveform = 0xFFFFFFFF;
sCtrlConfig.timing = 0xFFFFFFFF;
HAL_I3C_CTRL_SetConfig(&hi3c1, &sCtrlConfig);

// Configure stall time
HAL_I3C_CTRL_SetConfigStallTime(&hi3c1, 0x10, HAL_I3C_CTRL_STALL_CCC);

// Fill the private descriptor
hal_i3c_private_desc_t private_desc;
private_desc.tgt_addr = 0x22;
private_desc.data_size_byte = sizeof(tx_data);
private_desc.direction = HAL_I3C_DIRECTION_WRITE;

// Initialize transfer context
xfer_ctx.p_tc_data = NULL;
xfer_ctx.tc_size_word = 0;
xfer_ctx.p_tx_data = tx_data;
xfer_ctx.tx_size_byte = sizeof(tx_data);
xfer_ctx.p_rx_data = NULL;
xfer_ctx.rx_size_byte = 0;
xfer_ctx.transfer_mode = HAL_I3C_PRIVATE_WITH_ARB_RESTART;
xfer_ctx.nb_tx_frame = 1;









HAL_I3C_CTRL_InitTransferCtxTc(&xfer_ctx, ctrl_buf, 2);
HAL_I3C_CTRL_InitTransferCtxTx(&xfer_ctx, tx_buf, sizeof(tx_buf));

// Build CCC transfer context
HAL_I3C_CTRL_BuildTransferCtxPrivate(&xfer_ctx, &private_desc,
                                 1, HAL_I3C_PRIVATE_WITH_ARB_RESTART);





// Start the I3C transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_CTRL_Transfer(&hi3c1, &xfer_ctx, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CTRL_TransferCpltCallback */
HAL_I3C_CTRL_Transfer_IT(&hi3c1, &xfer_ctx);
HAL_I3C_CTRL_Transfer_DMA(&hi3c1, &xfer_ctx);

Key changes

  1. HAL2 applies controller configuration using HAL_I3C_CTRL_SetConfig() and configures stall time using HAL_I3C_CTRL_SetConfigStallTime().

  2. HAL2 builds a transfer context using HAL_I3C_CTRL_InitTransferCtx*() and HAL_I3C_CTRL_BuildTransferCtxPrivate().

  3. HAL2 starts the transfer using HAL_I3C_CTRL_Transfer*() instead of HAL_I3C_Ctrl_Transmit*().


Use case: HAL I3C controller private read

Sequence diagram

  @startuml
  participant "Application" as App
  participant "I3C" as I3C

  App -> I3C: HAL_I3C_Init()
  App -> I3C: HAL_I3C_Ctrl_Config()
  App -> I3C: HAL_I3C_AddDescToFrame()
  App -> I3C: HAL_I3C_Ctrl_Receive() / HAL_I3C_Ctrl_Receive_IT() / HAL_I3C_Ctrl_Receive_DMA()
  @enduml

Code snippet

HAL1

HAL2

I3C_HandleTypeDef hi3c1;
I3C_CtrlConfTypeDef sCtrlConfig = {0};
I3C_XferTypeDef xferData;
I3C_PrivateTypeDef privateDesc;
I3C_CCCTypeDef cccDesc;
uint8_t ccc_buffer[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t txBuffer[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t rx_buffer[8]  = {0};
uint32_t ctrlBuffer[2] = {0};
uint32_t status_buffer[2] = {0};

// Initialize I3C peripheral
hi3c1.Instance = I3C1;
hi3c1.Mode = HAL_I3C_MODE_CONTROLLER;
hi3c1.Init.CtrlBusCharacteristic.SDAHoldTime = HAL_I3C_SDA_HOLD_TIME_1_5;
hi3c1.Init.CtrlBusCharacteristic.WaitTime = HAL_I3C_OWN_ACTIVITY_STATE_0;
hi3c1.Init.CtrlBusCharacteristic.SCLPPLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI3CHighDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLODLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI2CHighDuration = 0x00;
hi3c1.Init.CtrlBusCharacteristic.BusFreeDuration = 0x32;
hi3c1.Init.CtrlBusCharacteristic.BusIdleDuration = 0xf8;
HAL_I3C_Init(&hi3c1);

// Configure controller
sCtrlConfig.DynamicAddr = 0;
sCtrlConfig.StallTime = 0x10;
sCtrlConfig.HotJoinAllowed = DISABLE;
sCtrlConfig.ACKStallState = DISABLE;
sCtrlConfig.CCCStallState = ENABLE;
sCtrlConfig.TxStallState = DISABLE;
sCtrlConfig.RxStallState = DISABLE;
sCtrlConfig.HighKeeperSDA = DISABLE;
HAL_I3C_Ctrl_Config(&hi3c1, &sCtrlConfig);

// Fill CCC descriptor
cccDesc.TargetAddr = 0x22;
cccDesc.CCC = 0x85;
cccDesc.CCCBuf.pBuffer = ccc_buffer;
cccDesc.CCCBuf.Size = sizeof(ccc_buffer);
cccDesc.Direction = 0;

// Fill Private descriptor
privateDesc.TargetAddr = 0x22;
privateDesc.TxBuf.pBuffer = txBuffer;
privateDesc.TxBuf.Size = sizeof(txBuffer);
privateDesc.RxBuf.pBuffer = rx_buffer;
privateDesc.RxBuf.Size = sizeof(rx_buffer);
privateDesc.Direction = 0;

// Fill transfer structure
xferData.CtrlBuf.pBuffer = ctrlBuffer;
xferData.CtrlBuf.Size = 2;
xferData.StatusBuf.pBuffer = status_buffer;
xferData.StatusBuf.Size = 2;
xferData.TxBuf.pBuffer = txBuffer;
xferData.TxBuf.Size = sizeof(txBuffer);
xferData.RxBuf.pBuffer = rx_buffer;
xferData.RxBuf.Size = sizeof(rx_buffer);

uint8_t nbFrame = 1;
uint32_t option = 0;

// Add descriptors to frame
HAL_StatusTypeDef status = HAL_I3C_AddDescToFrame(
    &hi3c1,
    &cccDesc,
    &privateDesc,
    &xferData,
    nbFrame,
    option
);

// Start transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_Ctrl_Receive(&hi3c1, &xferData, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CtrlRxCpltCallback */
HAL_I3C_Ctrl_Receive_IT(&hi3c1, &xferData);
HAL_I3C_Ctrl_Receive_DMA(&hi3c1, &xferData);
hal_i3c_handle_t hi3c1;
hal_i3c_ctrl_config_t sCtrlConfig;
hal_i3c_transfer_ctx_t xfer_ctx;
hal_i3c_ccc_desc_t ccc_desc;
uint32_t ctrl_buf[2] = {0x12345678, 0x9ABCDEF0};
uint8_t rx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t rx_data[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};















// Initialize I3C peripheral
HAL_I3C_Init(&hi3c1, HAL_I3C1);


// Configure controller
sCtrlConfig.scl_waveform = 0xFFFFFFFF;
sCtrlConfig.timing = 0xFFFFFFFF;
HAL_I3C_CTRL_SetConfig(&hi3c1, &sCtrlConfig);

// Configure stall time
HAL_I3C_CTRL_SetConfigStallTime(&hi3c1, 0x10, HAL_I3C_CTRL_STALL_CCC);

// Fill the private descriptor
hal_i3c_private_desc_t private_desc;
private_desc.tgt_addr = 0x22;
private_desc.data_size_byte = sizeof(rx_data);
private_desc.direction = HAL_I3C_DIRECTION_READ;

// Initialize transfer context
xfer_ctx.p_tc_data = NULL;
xfer_ctx.tc_size_word = 0;
xfer_ctx.p_tx_data = NULL;
xfer_ctx.tx_size_byte = 0;
xfer_ctx.p_rx_data = rx_data;
xfer_ctx.rx_size_byte = sizeof(rx_data);
xfer_ctx.transfer_mode = HAL_I3C_PRIVATE_WITH_ARB_RESTART;
xfer_ctx.nb_tx_frame = 1;









HAL_I3C_CTRL_InitTransferCtxTc(&xfer_ctx, ctrl_buf, 2);
HAL_I3C_CTRL_InitTransferCtxRx(&xfer_ctx, rx_buf, sizeof(rx_buf));

// Build CCC transfer context
HAL_I3C_CTRL_BuildTransferCtxPrivate(&xfer_ctx, &private_desc,
                                 1, HAL_I3C_PRIVATE_WITH_ARB_RESTART);





// Start the I3C transfer (choose one mode)
/* Polling mode: the function returns only when the transfer is complete */
HAL_I3C_CTRL_Transfer(&hi3c1, &xfer_ctx, 1000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CTRL_TransferCpltCallback */
HAL_I3C_CTRL_Transfer_IT(&hi3c1, &xfer_ctx);
HAL_I3C_CTRL_Transfer_DMA(&hi3c1, &xfer_ctx);

Key changes

  1. HAL2 applies controller configuration using HAL_I3C_CTRL_SetConfig() and configures stall time using HAL_I3C_CTRL_SetConfigStallTime().

  2. HAL2 builds a transfer context using HAL_I3C_CTRL_InitTransferCtx*() and HAL_I3C_CTRL_BuildTransferCtxPrivate().

  3. HAL2 starts the transfer using HAL_I3C_CTRL_Transfer*() instead of HAL_I3C_Ctrl_Receive*().


Use case: HAL I3C controller multiple direct CCC command

Sequence diagram

  @startuml
  participant "Application" as App
  participant "I3C" as I3C

  App -> I3C: HAL_I3C_Init()
  App -> I3C: HAL_I3C_Ctrl_Config()
  App -> I3C: HAL_I3C_AddDescToFrame()
  App -> I3C: HAL_I3C_Ctrl_MultipleTransfer_IT() / HAL_I3C_Ctrl_MultipleTransfer_DMA()
  @enduml

Code snippet

HAL1

HAL2

I3C_HandleTypeDef hi3c1;
I3C_CtrlConfTypeDef sCtrlConfig = {0};
I3C_XferTypeDef xferData;
I3C_PrivateTypeDef privateDesc;
I3C_CCCTypeDef cccDesc;
uint8_t ccc_buffer[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t tx_buffer1[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t rx_buffer1[8] = {0};
uint8_t tx_buffer2[4] = {0xA1, 0xB2, 0xC3, 0xD4};
uint8_t rx_buffer2[4] = {0};
uint32_t ctrlBuffer[2] = {0};
uint32_t status_buffer[2] = {0};

// Initialize I3C peripheral
hi3c1.Instance = I3C1;
hi3c1.Mode = HAL_I3C_MODE_CONTROLLER;
hi3c1.Init.CtrlBusCharacteristic.SDAHoldTime = HAL_I3C_SDA_HOLD_TIME_1_5;
hi3c1.Init.CtrlBusCharacteristic.WaitTime = HAL_I3C_OWN_ACTIVITY_STATE_0;
hi3c1.Init.CtrlBusCharacteristic.SCLPPLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI3CHighDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLODLowDuration = 0x7c;
hi3c1.Init.CtrlBusCharacteristic.SCLI2CHighDuration = 0x00;
hi3c1.Init.CtrlBusCharacteristic.BusFreeDuration = 0x32;
hi3c1.Init.CtrlBusCharacteristic.BusIdleDuration = 0xf8;
HAL_I3C_Init(&hi3c1);

// Configure controller
sCtrlConfig.DynamicAddr = 0;
sCtrlConfig.StallTime = 0x10;
sCtrlConfig.HotJoinAllowed = DISABLE;
sCtrlConfig.ACKStallState = DISABLE;
sCtrlConfig.CCCStallState = ENABLE;
sCtrlConfig.TxStallState = DISABLE;
sCtrlConfig.RxStallState = DISABLE;
sCtrlConfig.HighKeeperSDA = DISABLE;
HAL_I3C_Ctrl_Config(&hi3c1, &sCtrlConfig);

// Fill CCC descriptor
cccDesc.TargetAddr = 0x22;
cccDesc.CCC = 0x85;
cccDesc.CCCBuf.pBuffer = ccc_buffer;
cccDesc.CCCBuf.Size = sizeof(ccc_buffer);
cccDesc.Direction = 0;

// Tableau de descripteurs privés
I3C_PrivateTypeDef privateDescArray[2];

// Premier transfer
privateDescArray[0].TargetAddr = 0x22;
privateDescArray[0].TxBuf.pBuffer = txBuffer1;
privateDescArray[0].TxBuf.Size = sizeof(txBuffer1);
privateDescArray[0].RxBuf.pBuffer = rxBuffer1;
privateDescArray[0].RxBuf.Size = sizeof(rxBuffer1);
privateDescArray[0].Direction = 0; // Write

// Deuxième transfer
privateDescArray[1].TargetAddr = 0x33;
privateDescArray[1].TxBuf.pBuffer = txBuffer2;
privateDescArray[1].TxBuf.Size = sizeof(txBuffer2);
privateDescArray[1].RxBuf.pBuffer = rxBuffer2;
privateDescArray[1].RxBuf.Size = sizeof(rxBuffer2);
privateDescArray[1].Direction = 1; // Read

// Prepare transfer structure for the first transfer
I3C_XferTypeDef xferData1;
xferData1.CtrlBuf.pBuffer = ctrl_buffer;
xferData1.CtrlBuf.Size = 2;
xferData1.StatusBuf.pBuffer = status_buffer;
xferData1.StatusBuf.Size = 2;
xferData1.TxBuf.pBuffer = tx_buffer1;
xferData1.TxBuf.Size = sizeof(tx_buffer1);
xferData1.RxBuf.pBuffer = rx_buffer1;
xferData1.RxBuf.Size = sizeof(rx_buffer1);

// Prepare transfer structure for the second transfer
I3C_XferTypeDef xferData2;
xferData2.CtrlBuf.pBuffer = ctrl_buffer;
xferData2.CtrlBuf.Size = 2;
xferData2.StatusBuf.pBuffer = status_buffer;
xferData2.StatusBuf.Size = 2;
xferData2.TxBuf.pBuffer = tx_buffer2;
xferData2.TxBuf.Size = sizeof(tx_buffer2);
xferData2.RxBuf.pBuffer = rx_buffer2;
xferData2.RxBuf.Size = sizeof(rx_buffer2);

uint8_t nbFrame = 1;
uint32_t option = 0;

// Add descriptors to frame
HAL_StatusTypeDef status = HAL_I3C_AddDescToFrame(
    &hi3c1,
    &cccDesc,
    &privateDescArray,
    &xferData1,
    nbFrame,
    option
);

/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CtrlMultipleXferCpltCallback */
HAL_StatusTypeDef status1 = HAL_I3C_Ctrl_MultipleTransfer_IT(&hi3c, &xferData1);
HAL_StatusTypeDef status2 = HAL_I3C_Ctrl_MultipleTransfer_IT(&hi3c, &xferData2);
/* or in mode DMA */
HAL_I3C_Ctrl_MultipleTransfer_DMA(&hi3c, &xferData1);
HAL_I3C_Ctrl_MultipleTransfer_DMA(&hi3c, &xferData2);
hal_i3c_handle_t hi3c1;
hal_i3c_ctrl_config_t sCtrlConfig;
hal_i3c_transfer_ctx_t xfer_ctx;
hal_i3c_ccc_desc_t ccc_desc;
uint32_t ctrl_buf[2] = {0x12345678, 0x9ABCDEF0};
uint8_t tx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint8_t tx_data[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};















// Initialize I3C peripheral
HAL_I3C_Init(&hi3c1, HAL_I3C1);


// Configure controller
sCtrlConfig.scl_waveform = 0xFFFFFFFF;
sCtrlConfig.timing = 0xFFFFFFFF;
HAL_I3C_CTRL_SetConfig(&hi3c1, &sCtrlConfig);

// Configure stall time
HAL_I3C_CTRL_SetConfigStallTime(&hi3c1, 0x10, HAL_I3C_CTRL_STALL_CCC);

// Fill the private descriptor
hal_i3c_private_desc_t private_desc;
private_desc.tgt_addr = 0x22;
private_desc.data_size_byte = sizeof(tx_data);
private_desc.direction = HAL_I3C_DIRECTION_WRITE;

// Initialize transfer context
xfer_ctx.p_tc_data = NULL;
xfer_ctx.tc_size_word = 0;
xfer_ctx.p_tx_data = tx_data;
xfer_ctx.tx_size_byte = sizeof(tx_data);
xfer_ctx.p_rx_data = NULL;
xfer_ctx.rx_size_byte = 0;
xfer_ctx.transfer_mode = HAL_I3C_PRIVATE_WITH_ARB_RESTART;
xfer_ctx.nb_tx_frame = 1;









HAL_I3C_CTRL_InitTransferCtxTc(&xfer_ctx, ctrl_buf, 2);
HAL_I3C_CTRL_InitTransferCtxTx(&xfer_ctx, tx_buf, sizeof(tx_buf));

// Build CCC transfer context
HAL_I3C_CTRL_BuildTransferCtxPrivate(&xfer_ctx, &private_desc,
                                 1, HAL_I3C_PRIVATE_WITH_ARB_RESTART);





// Start the I3C transfer (choose one mode)
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_CTRL_TransferCpltCallback */
HAL_I3C_CTRL_Transfer_IT(&hi3c1, &xfer_ctx);
HAL_I3C_CTRL_Transfer_DMA(&hi3c1, &xfer_ctx);

Key changes

  1. HAL2 applies controller configuration using HAL_I3C_CTRL_SetConfig() and configures stall time using HAL_I3C_CTRL_SetConfigStallTime().

  2. HAL2 builds a transfer context using HAL_I3C_CTRL_InitTransferCtx*() and HAL_I3C_CTRL_BuildTransferCtxPrivate().

  3. HAL2 starts transfers using HAL_I3C_CTRL_Transfer_IT() / HAL_I3C_CTRL_Transfer_DMA() instead of HAL_I3C_Ctrl_MultipleTransfer_IT() / HAL_I3C_Ctrl_MultipleTransfer_DMA().


Use case: I3C target transmit in polling, interrupt and DMA mode

This use case shows how an I3C target transmits data in polling, interrupt, or DMA mode.

Sequence diagram

    @startuml
    participant "Application" as App
    participant "I3C" as I3C

    App -> I3C: HAL_I3C_Tgt_Transmit() / HAL_I3C_Tgt_Transmit_IT() / HAL_I3C_Tgt_Transmit_DMA()
    @enduml

Code snippet

HAL1

HAL2

I3C_HandleTypeDef hi3c;
I3C_XferTypeDef xferData;
uint32_t ctrlBuffer[2] = {0};
uint32_t status_buffer[2] = {0};

xferData.CtrlBuf = ctrlBuffer;
xferData.StatusBuf = status_buffer;

// Prepare data to transmit
uint8_t tx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
xferData.TxBuf.pData = tx_buf;
xferData.TxBuf.size = 8;

// Transmit data in target mode
HAL_StatusTypeDef status = HAL_I3C_Tgt_Transmit(&hi3c, &xferData, 5000);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_TgtTxCpltCallback */
HAL_I3C_Tgt_Transmit_IT(&hi3c, &xferData);
HAL_I3C_Tgt_Transmit_DMA(&hi3c, &xferData);
hal_i3c_handle_t hi3c;
uint8_t tx_buf[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
uint32_t timeout_ms = 5000;

// Transmit data in target mode
hal_status_t status = HAL_I3C_TGT_Transmit(&hi3c, tx_buf, sizeof(tx_buf), timeout_ms);
/* Interrupt and DMA modes: the operation is asynchronous and completion
will be notified to the user via HAL_I3C_TGT_TxCpltCallback */
HAL_I3C_TGT_Transmit_IT(&hi3c, tx_buf, sizeof(tx_buf));
HAL_I3C_TGT_Transmit_DMA(&hi3c, tx_buf, sizeof(tx_buf));

Key changes

  1. HAL2 uses renamed target APIs (HAL_I3C_TGT_Transmit*() instead of HAL_I3C_Tgt_Transmit*()).

  2. In HAL2, the target transmit API takes the buffer directly, instead of using I3C_XferTypeDef.